package com.raidpoints.client;

import gwtquery.plugins.draggable.client.DraggableOptions;
import gwtquery.plugins.draggable.client.DraggableOptions.HelperType;
import gwtquery.plugins.droppable.client.DroppableOptions.AcceptFunction;
import gwtquery.plugins.droppable.client.events.DragAndDropContext;
import gwtquery.plugins.droppable.client.events.DropEvent;
import gwtquery.plugins.droppable.client.events.DropEvent.DropEventHandler;
import gwtquery.plugins.droppable.client.gwt.DragAndDropCellList;
import gwtquery.plugins.droppable.client.gwt.DroppableWidget;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;

public class SlottingBox extends DialogBox {
	public static int bcount=0;
	RaidPoints rp;
	event evt;
	ArrayList<character> charlist;
	HashMap<String,CellList<character>> rolemap;
	HashMap<DroppableWidget<DragAndDropCellList<character>>,String> rerolemap;
	HashMap<String,ListDataProvider<character>> datamap;
	HorizontalPanel hpan;
	DockLayoutPanel dp;
	HorizontalPanel bpan;
	VerticalPanel vpans;
	Label distinctLabel, slottedLabel, subLabel;
	AsyncCallback<ArrayList<character>> charCallback;
	int slotted;
	HashMap<Integer,Integer> submap; 
	HashMap<Integer,Integer> resubmap;
	Integer[] subcount;
	int cuid;

	public class DropHandler implements DropEventHandler {

		@Override
		public void onDrop(DropEvent event) {
			DroppableWidget<DragAndDropCellList<character>> dw = (DroppableWidget<DragAndDropCellList<character>>)event.getDroppableWidget();
			character tc = event.getDraggableData();
			for(character mc : datamap.get(tc.slotrole).getList()){
				if(mc.cid == tc.cid){
					datamap.get(tc.slotrole).getList().remove(mc);
				}
			}
			tc.slotrole = rerolemap.get(dw);
			datamap.get(rerolemap.get(dw)).getList().add(tc);
		}

	}

	public SlottingBox(RaidPoints mrp, event mevt, boolean isCL) {
		bcount++;
		this.getElement().setId("dropdialog" + bcount);
		setHTML("Slotting");
		cuid = -1;
		rolemap = new HashMap<String,CellList<character>>();
		rerolemap = new HashMap<DroppableWidget<DragAndDropCellList<character>>,String>();
		datamap = new HashMap<String,ListDataProvider<character>>();
		charlist = new ArrayList<character>();
		submap = new HashMap<Integer,Integer>();
		resubmap = new HashMap<Integer,Integer>();
		rp = mrp; 
		evt = mevt;
		slotted = 0;
		setSize("800px","650px");
		hpan = new HorizontalPanel(); bpan = new HorizontalPanel();
		hpan.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
		dp = new DockLayoutPanel(Unit.PX);
		vpans = new VerticalPanel();
		setWidget(vpans);
		//hpan.setHeight("600px");
		//	dp.addSouth(bpan,100);
		//dp.add(hpan);
		vpans.add(hpan);
		vpans.add(bpan);

		Button saveButton = new Button("Save");
		Button closeButton = new Button("Close");
		Button regButton = new Button("Reg. Check");
		final CheckBox publishBox = new CheckBox("Publish");
		publishBox.setValue(mevt.publish);
		Label cns = new Label();
		if(rp.auth != RaidPoints.AuthType.admin && !isCL){
			saveButton.setVisible(false);
			publishBox.setVisible(false);
			regButton.setVisible(false);
			cns.setText("You do not have admin rights for this event. Slotting cannot be saved.");
		}
		else{
			cns.setVisible(false);
		}
		distinctLabel = new Label();
		slottedLabel = new Label();
		subLabel = new Label();
		bpan.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		bpan.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		bpan.setSpacing(10);
		bpan.add(distinctLabel); bpan.add(slottedLabel);
		if(evt.split < 0) bpan.add(subLabel);
		bpan.add(publishBox); bpan.add(regButton); bpan.add(saveButton); bpan.add(cns); bpan.add(closeButton);
		if(evt.creator > 0) regButton.setVisible(false);

		if(evt.split < 0){
			String[] subsplit = evt.mynote.split(",");
			submap.put(0, 1);
			resubmap.put(1,0);
			for(int i = 0; i < subsplit.length; i++){
				submap.put(Integer.parseInt(subsplit[i]), i+2);
				resubmap.put(i+2, Integer.parseInt(subsplit[i]));
			}
			subcount = new Integer[submap.size()];
			for(int z = 0; z < subcount.length; z++) subcount[z] = 0;
		}

		closeButton.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				hide();
			}
		});

		regButton.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				RegularBox rb = new RegularBox();
				rb.center(); rb.show();
			}
		});

		final AsyncCallback<String> saveCallback = new AsyncCallback<String>(){

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onSuccess(String result) {
				hide();				
			}

		};

		saveButton.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				rp.rpsvc.SendSlotList(evt, charlist, publishBox.getValue(), saveCallback);
			}
		});

		charCallback = new AsyncCallback<ArrayList<character>>(){

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onSuccess(ArrayList<character> result) {
				if(result == null) return;
				HashSet<Integer> uniqueid = new HashSet<Integer>();
				charlist.clear();
				slotted = 0;
				for(String rl : rolemap.keySet()) datamap.get(rl).getList().clear();
				for(character c: result){
					if(c.slot.equals("slotted")) {
						c.clicked = true; 
						slotted++;
						if(evt.split < 0) subcount[submap.get(c.subraid) - 1]++;
					}
					if(c.slotrole == null || c.slotrole.equals("")) c.slotrole=datamap.keySet().iterator().next();
					datamap.get(c.slotrole).getList().add(c);
					charlist.add(c);
					if(c.uid > 0) uniqueid.add(c.uid);
				}
				for(character c: result){
					if(c.clicked) CrossoutND(c); 
				}
				distinctLabel.setText("Distinct Signups: " + uniqueid.size());
				dp.forceLayout();
				slottedLabel.setText("Slotted: " + slotted);
				if(evt.split < 0) MakeLabel();
			}

		};

		AsyncCallback<String> roleCallback = new AsyncCallback<String>(){

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onSuccess(String result) {
				if(result.equals("")) return;
				String[] split = result.split(",");
				SlotCell msc = new SlotCell();
				for(int i = 0; i < split.length; i++){
					//			CellList<character> tl = new CellList<character>(msc);

					DragAndDropCellList<character> tl = new DragAndDropCellList<character>(msc);
					tl.setCellDraggableOnly();
					DroppableWidget<DragAndDropCellList<character>> dw = new DroppableWidget<DragAndDropCellList<character>>(tl);
					dw.addDropHandler(new DropHandler());
					dw.setDroppableHoverClass("slotdrag");
					dw.setAccept(new AcceptFunction(){
						@Override
						public boolean acceptDrop(DragAndDropContext context) {
							// TODO Auto-generated method stub
							return true;
						}
					});

					DraggableOptions options = new DraggableOptions();
					options.setHelper(HelperType.CLONE);
					options.setOpacity((float) 0.9);
					options.setAppendTo("#dropdialog" + bcount);
					tl.setDraggableOptions(options);


					//					final SingleSelectionModel<character> ssm = new SingleSelectionModel<character>();
					//					tl.setSelectionModel(ssm);
					//					ssm.addSelectionChangeHandler(new SelectionChangeEvent.Handler(){
					//
					//						@Override
					//						public void onSelectionChange(SelectionChangeEvent event) {
					//							ssm.
					//						}
					//						
					//					});

					ListDataProvider<character> tdp = new ListDataProvider<character>();
					tdp.addDataDisplay(tl);
					//tl.sinkEvents(Event.ONMOUSEOVER);
					rolemap.put(split[i],tl);
					rerolemap.put(dw,split[i]);
					datamap.put(split[i], tdp);
					VerticalPanel vpan = new VerticalPanel();
					ScrollPanel span = new ScrollPanel();
					span.setStyleName("slotlist");
					tl.setStyleName("slotlist");
					//span.setAlwaysShowScrollBars(true);
					span.add(dw);
					vpan.add(new HTML("<font size=\"3\">" + split[i] + ":</font>")); vpan.add(span);
					hpan.add(vpan);
					tl.setWidth(split.length > 4 ? "200px" : "250px");
					tl.setHeight("500px");
					dp.forceLayout();
				}
				//	rp.rpsvc.GetSlotList(evt, charCallback);
			}

		};

		rp.rpsvc.GetRoles(evt, roleCallback);
	}

	public void MakeLabel(){
		subLabel.setText("");
		for(int i = 0; i < subcount.length; i++){
			subLabel.setText(subLabel.getText() + (i == 0 ? "" : " ") + "Group " + (i+1) + ": " + subcount[i]);
		}
	}

	public void GetChars(){
		rp.rpsvc.GetSlotList(evt, charCallback);
	}

	public void CrossoutND(character c){
		int count = 0;
		int ccount = 0;
		for(character tc : charlist){
			if(tc.uid > 0 && (tc.uid == c.uid)) {
				count++;
				if(tc.clicked) ccount++; 
			}
		}
		if(count > 1){
			for(character tc : charlist){
				if(tc.uid > 0 && (tc.uid == c.uid))
					if(ccount == 1 && !tc.clicked) tc.hovered = true;
					else if(ccount > 1) tc.hovered  = true;
					else tc.hovered = false;
			}
		}
	}

	public void Crossout(character c){
		int count = 0;
		int ccount = 0;
		for(character tc : charlist){
			if(tc.uid > 0 && (tc.uid == c.uid)) {
				count++;
				if(tc.clicked) ccount++; 
			}
		}
		if(count > 1){
			for(character tc : charlist){
				if(tc.uid > 0 && (tc.uid == c.uid))
					if(ccount == 1 && !tc.clicked) tc.hovered = true;
					else if(ccount > 1) tc.hovered  = true;
					else tc.hovered = false;
			}
		}
		slottedLabel.setText("Slotted: " + slotted);
		if(evt.split < 0) MakeLabel();
		ReDraw();
	}

	public void ReDraw(){
		for(String s : rolemap.keySet()) rolemap.get(s).redraw();
	}

	public class SlotCell extends AbstractCell<character>{

		boolean clicked;

		public SlotCell(){
			//super("click","contextmenu","mouseenter","mouseout","mouseleave","mouseover");
			super("click","contextmenu");
			clicked = false;
		}

		@Override
		public void onBrowserEvent(Context context, Element parent, character value, NativeEvent event,ValueUpdater<character> valueUpdater) {
			if(event.getType().equals("contextmenu")){
				RoleBox rb = new RoleBox(value);
				rb.setPopupPosition(event.getClientX(), event.getClientY());
				rb.show();
				event.preventDefault();
				event.stopPropagation();
				return;
			}
			super.onBrowserEvent(context, parent, value, event, valueUpdater);
			//GWT.log(event.getEventTarget().toString());
//			if(event.getType().equals("mouseover") || event.getType().equals("mouseenter")){
//				if(value.uid != cuid && value.ngsid > 0 && event.getEventTarget().toString().equals("[object HTMLFontElement]")){
//					cuid = value.uid;
//					ReDraw();
//				}
//			}
//			else if(event.getType().equals("mouseout") || event.getType().equals("mouseleave")){
//				if(cuid > 0){
//					cuid = -1;
//					ReDraw();
//				}
//			}
			if ("click".equals(event.getType()) && !event.getEventTarget().toString().equals("[object HTMLImageElement]")) {
				// Ignore clicks that occur outside of the outermost element.
				EventTarget eventTarget = event.getEventTarget();
				if (parent.getFirstChildElement().isOrHasChild(Element.as(eventTarget))) {
					//if(!value.hovered) {
					if(evt.split >= 0){
						value.clicked = !value.clicked;
						if(value.clicked) slotted++;
						else slotted--;
						value.slot = value.clicked ? "slotted" : "standby";
					}
					else{
						if(!value.slot.equals("slotted")){
							value.slot = "slotted";
							value.subraid = 0;
							subcount[0]++;
							slotted++;
							value.clicked = true;
						}
						else{
							int cnum = submap.get(value.subraid);
							if(cnum == submap.size()){ //is last in list
								value.slot = "standby";
								value.subraid = 0;
								slotted--;
								subcount[subcount.length - 1]--;
								value.clicked = false;
							}
							else{
								value.subraid = resubmap.get(cnum + 1);
								subcount[cnum-1]--;
								subcount[cnum]++;
							}
						}
					}
					Crossout(value);
					//  }
					//doAction(value, valueUpdater);
				}
				//  event.stopPropagation();
				// event.preventDefault();
			}
			//			 else{
			//				 super.onBrowserEvent(context, parent, value, event, valueUpdater);
			//			 }
			//			


		}


		@Override
		public void render(com.google.gwt.cell.client.Cell.Context context, character value, SafeHtmlBuilder sb) {
			if(value == null) return;
			String icon = "";
			if(value.gid == 1) icon = "<a href=\"http://us.battle.net/wow/en/character/silver-hand/" + value.name + "/advanced\" target=_blank><img src=\"cicons/" + (value.Class == null ? "mage" : value.Class.toLowerCase().replace(" ", "") ) + ".png\" width=\"48\" height=\"48\"></a>";
			else if(value.gid == 2 || value.gid == 5) icon = "<img src=\"cicons/" + RaidPoints.GetCicon(value) + ".png\" width=\"48\" height=\"48\">";
			String name = value.name;
			if(evt.split < 0 && value.slot.equals("slotted")) name = value.name + " - " + submap.get(value.subraid);
			if(value.hovered) name = "<STRIKE>" + name + "</STRIKE>";
			//if(value.canceled)  name = "<font size=\"3\" style=\"background-color: red;\">" + name + "</font>";
		//	String outline = "";
		//	if(value.canceled) outline = " style=\"outline:red solid 4px;\"";
			//if(value.uid == cuid) outline = " style=\"outline:blue solid 4px;\"";
			if(value.clicked) name = "<font size=\"3\" style=\"background-color: #00CC00;" + (value.canceled ? " outline:red solid 4px;" : "") +"\">" + name + "</font>";
			else name = "<font size=\"3\""+ (value.canceled ? " style=\"outline:red solid 4px;\"" : "") + ">" + name + "</font>";
			//if(value.uid == cuid) name = "<b>" + name + "</b>";
			//GWT.log("Rendering " + value.name);
			//sb.appendHtmlConstant ("<div style=\"background-color:green; border: 1px solid black;\">");
			sb.appendHtmlConstant("<table>");
			sb.appendHtmlConstant("<tr><td rowspan='3'>");
			sb.appendHtmlConstant(icon);
			sb.appendHtmlConstant("</td>");

			sb.appendHtmlConstant("<td>");
			sb.appendHtmlConstant((value.canceled ? "&nbsp": "") + name);
			sb.appendHtmlConstant("</td></tr><tr><td>");
			sb.appendEscaped(value.note);
			sb.appendHtmlConstant("</td></tr></table>");
			//sb.appendHtmlConstant ("</div>");

		}



	}

	public class RegularBox extends DialogBox{
		ListBox reglist;
		Button closeButton;

		RegularBox(){
			VerticalPanel vpan = new VerticalPanel();
			reglist = new ListBox();
			reglist.setSize("120px","90px");
			reglist.setEnabled(false);
			reglist.setVisibleItemCount(10);
			closeButton = new Button("Close");
			vpan.setHeight("90px"); vpan.setWidth("120px");
			setWidget(vpan);

			vpan.add(reglist); vpan.add(closeButton);

			closeButton.addClickHandler(new ClickHandler(){
				@Override
				public void onClick(ClickEvent event) {
					hide();					
				}		
			});

			AsyncCallback<ArrayList<String>> regCallback = new AsyncCallback<ArrayList<String>>(){

				@Override
				public void onFailure(Throwable caught) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onSuccess(ArrayList<String> result) {
					reglist.clear();
					for(String s: result) reglist.addItem(s);
				}

			};
			rp.rpsvc.GetRegulars(evt, regCallback);
		}

	}

	public class RoleBox extends PopupPanel{
		HTML rlabel;
		public RoleBox(final character mc){
			super(true);
			rlabel = new HTML();
			rlabel.setHTML("Primary: " + mc.prole);
			setWidget(rlabel);

			AsyncCallback<String> infoCallback = new AsyncCallback<String>(){

				@Override
				public void onFailure(Throwable caught) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onSuccess(String result) {
					if(result == null || result.equals("")) return;
					rlabel.setHTML("Primary: " + mc.prole + "<br>" + result);
				}
			};
			rp.rpsvc.AdditionalCharInfo(mc.cid, infoCallback);			
		}
	}

}
